import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/events.dart';

import '../../components/operation.dart';
import '../../components/pile.dart';
import '../klondike_world.dart';
import 'waste_pile.dart';
import '../klondike_game.dart';
import '../../components/card.dart';

class StockPile extends PositionComponent 
  with TapCallbacks, HasGameReference<KlondikeGame>, HasWorldReference<KlondikeWorld>
  implements Pile {

  StockPile({super.position}) : super(size: KlondikeGame.cardSize);

  final List<Card> _cards = [];

  final _borderPaint = Paint()
    ..style = PaintingStyle.stroke
    ..strokeWidth = 10
    ..color = const Color(0xFF3F5B5D);
  final _circlePaint = Paint()
    ..style = PaintingStyle.stroke
    ..strokeWidth = 100
    ..color = const Color(0x883F5B5D);

  @override
  void render(Canvas canvas) {
    canvas.drawRRect(KlondikeGame.cardRRect, _borderPaint);
    canvas.drawCircle(
      Offset(width / 2, height / 2),
      KlondikeGame.cardWidth * 0.3,
      _circlePaint,
    );
  }

  @override
  bool canMoveCard(List<Card> cards) => false;

  @override
  bool canAcceptCard(List<Card> cards) => false;

  @override
  void removeCard(List<Card> cards) {
    for(Card card in cards) {
      assert(card.isFaceDown);
      _cards.remove(card);
    }
  }

  @override
  void acquireCard(List<Card> cards) {
    for(Card card in cards) {
      assert(card.isFaceDown);
      card.position = position;
      card.priority = _cards.length;
      _cards.add(card);
      card.pile = this;
    }
  }

  @override
  void returnCard(List<Card> cards) => throw StateError('cannot remove cards from here.');

  @override
  PositionComponent top() => throw StateError('cannot find top from here.');

  
  @override
  void onTapUp(TapUpEvent event) {
    handle();
  }

  @override
  void handleTapUp(Card card) {
    handle();
  }

  Future<void> handle() async {
    final wastePile = parent!.firstChild<WastePile>()!;
    if(_cards.isEmpty) {
      List<Card> cards = wastePile.getAllCards();
      Operation operation = Operation(cards, wastePile, this);
        operation.middleProcess = () {
          operation.cards = operation.cards.reversed.toList();
          for(Card card in cards) {
            if(card.isFaceUp) {
              card.flip();
            }
          }
        };
        operation.middleRevoke = () {
          operation.cards = operation.cards.reversed.toList();
          for(Card card in operation.cards) {
            if(card.isFaceDown) {
              card.flip();
            }
          }
        };
      await operation.proceed();
      // record to revoke
      world.histories.add(operation);

    } else {
      int removeIndex = _cards.length - game.fanoutNum;
      if(removeIndex < 0) {
        removeIndex = 0;
      }
      List<Card> removeCards = _cards.sublist(removeIndex);

      Operation operation = Operation(removeCards, this, wastePile);
        operation.middleProcess = () {
          operation.cards = operation.cards.reversed.toList();
          for(Card card in operation.cards) {
            if(card.isFaceDown) {
              card.flip();
            }
          }
        };
        operation.middleRevoke = () {
          operation.cards = operation.cards.reversed.toList();
          for(Card card in operation.cards) {
            if(card.isFaceUp) {
              card.flip();
            }
          }
        };
      
      await operation.proceed();
      world.histories.add(operation);
    }
  }

  @override
  Future<bool> tryToMove() async => throw StateError('cannot move from here.');
}